#!/usr/bin/env python3
# coding=utf-8

import sys
import os

class JarDependency:
    def __init__(self, groupId, artifactId, version, packaging, depth):
        self.__groupId = groupId
        self.__artifactId = artifactId
        self.__version = version
        self.__packaging = packaging
        self.__classifier = ''
        self.__scope = ''
        self.__depth = depth
        self.__parent = None
        self.__children = []
    @property
    def groupId(self):
        return self.__groupId
    @property
    def artifactId(self):
        return self.__artifactId
    @property
    def version(self):
        return self.__version
    @property
    def packaging(self):
        return self.__packaging
    @property
    def id(self):
        return self.__id
    @id.setter
    def id(self, id):
        self.__id = id
    @property
    def scope(self):
        return self.__scope
    @scope.setter
    def scope(self, scope):
        self.__scope = scope
    @property
    def classifier(self):
        return self.__classifier
    @classifier.setter
    def classifier(self, classifier):
        self.__classifier = classifier
    @property
    def depth(self):
        return self.__depth
    @property
    def parent(self):
        return self.__parent
    @parent.setter
    def parent(self, parent):
        self.__parent = parent
        parent.__children.append(self)
    @property
    def children(self):
        return self.__children
    @property
    def idPath(self):
        if(self.parent):
            return self.parent.idPath + '|' + str(self.id)
        else:
            return str(self.id)
    @property
    def shortNamePath(self):
        if(self.parent):
            return self.parent.shortNamePath + '|' + self.shortName
        else:
            return self.shortName
    @property
    def shortName(self):
        return self.__groupId + ':' + self.__artifactId
    def __str__(self):
        if(self.__classifier):
            return self.__groupId + ':' + self.__artifactId +'-'+ self.__version  +'-'+ self.__classifier + '.' + self.__packaging
        else:
            return self.__groupId + ':' + self.__artifactId +'-'+ self.__version + '.' + self.__packaging
class Stack(object):
    def __init__(self):
        self.__stack = []
    def push(self, data):
        self.__stack.append(data)
    def pop(self):
        return self.__stack.pop()
    def peek(self):
        return self.__stack[-1]
    def is_empty(self):
        return len(self.__stack) == 0
    def bottom(self):
        v = None
        while(len(self.__stack)>0):
            v = self.pop()
        return v

class JarDependencyParser:
    def parse(self, filename):
        with open(filename, 'rt', encoding='utf-8') as f:
            lines = f.readlines()
            stack = Stack()
            for line in lines:
                line = self.__extract(line)
                indent = self.__indent(line)
                depJar = self.__build_dependency(line, indent)
                self.__layer(depJar, stack)
            root = stack.bottom()
            return root
    def __layer(self, depJar, stack):
        if(stack.is_empty()):
            stack.push(depJar)
        else:
            while stack.peek().depth>depJar.depth:
                stack.pop()
            peek = stack.peek()
            if peek.depth < depJar.depth:
                depJar.parent = peek
            else:
                depJar.parent = peek.parent
            stack.push(depJar)
    def __extract(self, line):
        return line.replace('[INFO] ','').replace('\n','')
    def __indent(self, line):
        i=0
        for c in line:
            if self.__name(ord(c)):
                break
            i += 1
        return i
    def __build_dependency(self, line, indent):
        # com.yonyoucloud:uretail-web:war:2.0.0-SNAPSHOT
        # com.yonyoucloud:uretail-business:jar:2.0.0-SNAPSHOT:compile
        # net.sf.json-lib:json-lib:jar:jdk15:2.4:compile
        depth = int(indent / 3)
        arr = line[indent:].split(':')
        if len(arr) == 4:
            return JarDependency(arr[0], arr[1],arr[3],arr[2], depth)
        elif len(arr) == 5:
            dep = JarDependency(arr[0], arr[1],arr[3],arr[2], depth)
            dep.scope = arr[4]
            return dep
        elif len(arr) == 6:
            dep = JarDependency(arr[0], arr[1],arr[4],arr[2], depth)
            dep.classifier = arr[3]
            dep.scope = arr[5]
            return dep
        else:
            raise Exception('unrecognized dependecy string: ' + line)
    def __name(self, c):
        return c>=97 and c<=122
class DependencySqlBuilder:
    def __init__(self, root, sqlfile):
        self.__root = root
        self.__sqlfile = sqlfile
    def init_id(self, node, id):
        self.__counter = id
        self.__init_id_inner(node)
    def __init_id_inner(self, parent):
        parent.id = self.__counter
        self.__counter += 1
        if(parent.children):
            for child in parent.children:
                self.__init_id_inner(child)
    def build(self):
        service_component = str(self.__root)
        with open(self.__sqlfile,'wt',encoding='utf-8') as f:
            self.__write_sql(f, self.__root, service_component)
        
    def __write_sql(self, file, node, service_component):
        file.write('insert into component_dependencies(id, service_component, group_id, artifact_id, version, packaging, classifier , scope , depth, id_path, short_name_path, parent, parent_short_name, parent_id)')
        file.write(" values (%(id)d,'%(service_component)s', '%(group_id)s', '%(artifact_id)s', '%(version)s', '%(packaging)s', '%(classifier)s', '%(scope)s', %(depth)d, '%(id_path)s', '%(short_name_path)s', '%(parent)s', '%(parent_short_name)s', %(parent_id)d);" % {'id':node.id, 'service_component':service_component, 'group_id':node.groupId, 'artifact_id':node.artifactId, 'version':node.version, 'packaging':node.packaging, 'classifier':node.classifier , 'scope':node.scope , 'depth':node.depth, 'id_path':node.idPath, 'short_name_path':node.shortNamePath, 'parent':node.parent or '', 'parent_short_name':node.parent and node.parent.shortName or '', 'parent_id':node.parent and node.parent.id or 0})
        file.write('\n')
        if node.children:
            for child in node.children:
                self.__write_sql(file, child, service_component)
